package javax.realtime;

public class PeriodicTimer extends Timer {
	/*
	public static void main(String[] args)
	{
		PeriodicTimer timer = new PeriodicTimer(null, new RelativeTime(1000, 0), null);
		long notifytime = System.nanoTime();
		System.out.println("notify, time " + notifytime / 1000000000 + "s, " + notifytime % 1000000000 / 1000000 + "ms, " + notifytime % 1000000 / 1000 + "us, " + notifytime % 1000 + "ns");
		timer.start();
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private static class ThePeriodicTimer {
		private static class TimerThread extends java.lang.Thread {
			private static ArrayList<Object> timeList = new ArrayList<Object>();
			private static Object lock = new Object();
			private static Clock clock = Clock.getRealtimeClock();
			private boolean firstrun = true;
			public void insert()
			{
				;
			}
			@Override
			public void run()
			{
				NativeHelper.setpriority(0, NativeHelper.getMaxTimerPriority());
				long millis = 0;
				int nanos = 0;
				
				while(true)
				{
					if(timeList.size() == 0)
					{
						synchronized(this)
						{
							try {
								this.wait();
							} catch (InterruptedException e) {}
						}
					}
					//
						try {
							sleep(millis, nanos);
						} catch (InterruptedException e) {throw new RuntimeException("Possible time drift detected");}
				}
			}
		}
		private static ThePeriodicRTCTimer instance = new ThePeriodicRTCTimer();
		private static Object lock = new Object();
		
		
		private ThePeriodicRTCTimer()
		{
		}
		public static ThePeriodicRTCTimer instance()
		{
			return instance;
		}
		public static synchronized void add()
		{
			;
		}
	}
	*/
	
	//private ThePeriodicRTCTimer theTimer = ThePeriodicRTCTimer.instance();
	
	private  class PeriodicSleep extends java.lang.Thread {
		private PeriodicTimer timer_to_notify;
		private RelativeTime desired;
		private AbsoluteTime desiredTime;
		public boolean running = true;
		public PeriodicSleep(PeriodicTimer timer_to_notify)
		{
			this(timer_to_notify, new RelativeTime());
		}
		public PeriodicSleep(PeriodicTimer timer_to_notify, RelativeTime desiredAmount)
		{
			this.timer_to_notify = timer_to_notify;
			desired = desiredAmount;
		}
		public void set(long millis, int nanos)
		{
			if(nanos < 0 || millis < 0 || (nanos == 0 && millis == 0)) throw new IllegalArgumentException();
			desired.set(millis,nanos);
		}
		@Override
		public void run()
		{
			NativeHelper.setpriority(0, NativeHelper.getMaxTimerPriority());
			
			long new_millis = desired.milliseconds;
			long new_nanos = desired.nanoseconds;
			//desiredTime = System.nanoTime() + millis_in_nanos;
			desiredTime = desired.clock.getTime();
			while(running)
			{
				NativeHelper.nanosleep(new_millis, new_nanos);
				if(timer_to_notify.enabled)
					timer_to_notify._notify();
				desiredTime = desiredTime.add(desired);
				RelativeTime delta = desiredTime.clock.getTime().subtract(desiredTime);
				//RelativeTime delta = actual.subtract(desired);
				RelativeTime newDesired = desired.subtract(delta);
				new_millis = newDesired.milliseconds;
				new_nanos = newDesired.nanoseconds;
				//System.out.println("delta " + delta);
				//System.out.println("new " + new_millis + "ms, new " + new_nanos + "ns");
			}
			/*
			while(running)
			{
				NativeHelper.nanosleep(millis, nanos);
			}*/
		}	
	}
	
	private RelativeTime interval;
	private PeriodicSleep the_sleeping_beauty;
	private RealtimeThread thread = null;
	
	public PeriodicTimer(HighResolutionTime start, RelativeTime interval, AsyncEventHandler handler)
	{
		this(start, interval, interval.getClock(), handler);
	}
	public PeriodicTimer(HighResolutionTime start, RelativeTime interval, Clock clock, AsyncEventHandler handler)
	{
		//TODO: start & clock & handler association
		super(start, clock, handler);
		the_sleeping_beauty = new PeriodicSleep(this);
		/*
		if(start instanceof AbsoluteTime) nextStart = (AbsoluteTime)start;
		else if(start instanceof RelativeTime) nextStart = clock.getTime().add((RelativeTime)start);
		else nextStart = new AbsoluteTime(0,0,clock);
		*/
		this.interval = interval;
		the_sleeping_beauty.set(interval.milliseconds, interval.nanoseconds);
	}
	public PeriodicTimer(HighResolutionTime start, RelativeTime interval, Clock clock, AsyncEventHandler handler, RealtimeThread thread)
	{
		this(start, interval, clock, handler);
		this.thread = thread;
	}
	
	public ReleaseParameters createReleaseParameters()
	{
		//TODO: stub
		return null;
	}
	public Clock getClock()
	{
		return clock;
	}
	public AbsoluteTime getFireTime()
	{
		//TODO: stub
		//return nextStart;
		return null;
	}
	public AbsoluteTime getFireTime(AbsoluteTime dest)
	{
		dest.set(getFireTime());
		return dest;
	}
	public RelativeTime getInterval()
	{
		return interval;
	}
	public void setInterval(RelativeTime interval)
	{
		if(interval.milliseconds < 0 || interval.nanoseconds < 0) throw new IllegalArgumentException();
		this.interval = interval;
		the_sleeping_beauty.set(interval.milliseconds, interval.nanoseconds);
	}
	public void start()
	{
		super.start();
		the_sleeping_beauty.start();
	}
	public void _notify()
	{
		/*
		long notifytime = System.nanoTime();
		System.out.println("notify, time " + notifytime / 1000000000 + "s, " + notifytime % 1000000000 / 1000000 + "ms, " + notifytime % 1000000 / 1000 + "us, " + notifytime % 1000 + "ns");
		*/
		if(thread != null)
		{
			Scheduler scheduler = thread.getScheduler();
			if(scheduler instanceof esrc.c9cf.Scheduler)
			{
				//System.out.println("Reschedule from PT._notify()");
				//((esrc.c9cf.Scheduler)scheduler).reschedule();
				((esrc.c9cf.Scheduler)scheduler).reschedule(Clock.getRealtimeClock().getTime(), thread);
			}
		}
	}
	@Override
	public boolean stop()
	{
		super.stop();
		the_sleeping_beauty.running = false;
		try {
			the_sleeping_beauty.join();
		} catch (InterruptedException e) {
		}
		return true;
	}
}
